part of 'analysis_image.dart';

extension Nv21Converter on Nv21Image {
  /// Converts the image to a [JpegImage], helping when one wants to display it
  /// or make JPEG treatment on it.
  Future<JpegImage> toJpeg({
    int quality = 100,
  }) async {
    final jpegQuality = quality.clamp(0, 100);
    final wrappedImage = await AnalysisImageUtils().nv21toJpeg(
      wrapped(),
      jpegQuality,
    );
    return wrappedImage.unwrap() as JpegImage;
  }
}

extension Yuv420Converter on Yuv420Image {
  /// Converts the image to a [JpegImage], helping when one wants to display it
  /// or make JPEG treatment on it.
  Future<JpegImage> toJpeg({
    int quality = 100,
  }) async {
    final jpegQuality = quality.clamp(0, 100);
    final wrappedImage = await AnalysisImageUtils().yuv420toJpeg(
      wrapped(),
      jpegQuality,
    );
    return wrappedImage.unwrap() as JpegImage;
  }

  /// Converts the image to a [Nv21Image].
  Future<Nv21Image> toNv21() async {
    final wrappedImage = await AnalysisImageUtils().yuv420toNv21(
      wrapped(),
    );
    return wrappedImage.unwrap() as Nv21Image;
  }
}

extension Bgra8888Converter on Bgra8888Image {
  Future<JpegImage> toJpeg({
    int quality = 100,
  }) async {
    // TODO Not implemented on the native side
    final jpegQuality = quality.clamp(0, 100);
    final wrappedValue = wrapped();
    final wrappedImage = await AnalysisImageUtils().bgra8888toJpeg(
      wrappedValue,
      jpegQuality,
    );
    return wrappedImage.unwrap() as JpegImage;
  }
}

/// Wraps (converts) the [AnalysisImage] to a [AnalysisImageWrapper].
/// [AnalysisImageWrapper] is generated by pigeon and should not be handled by
/// end-user.
extension AnalysisWrapper on AnalysisImage {
  AnalysisImageWrapper wrapped() {
    return AnalysisImageWrapper(
      height: height,
      width: width,
      format: AnalysisImageFormat.values.byName(format.name),
      bytes: when<Uint8List?>(
        nv21: (image) => image.bytes,
        bgra8888: (image) => image.bytes,
        jpeg: (image) => image.bytes,
        yuv420: (image) => null,
      ),
      planes: when<List<PlaneWrapper>?>(
        nv21: (image) => image.planes.map((e) => e.wrapped()).toList(),
        bgra8888: (image) => image.planes.map((e) => e.wrapped()).toList(),
        jpeg: (image) => null,
        yuv420: (image) => image.planes.map((e) => e.wrapped()).toList(),
      ),
      cropRect: when<CropRectWrapper?>(
        nv21: (image) => CropRectWrapper(
          left: image.cropRect.left.toInt(),
          top: image.cropRect.top.toInt(),
          width: image.cropRect.width.toInt(),
          height: image.cropRect.height.toInt(),
        ),
        bgra8888: (image) => null,
        jpeg: (image) => null,
        yuv420: (image) => CropRectWrapper(
          left: image.cropRect.left.toInt(),
          top: image.cropRect.top.toInt(),
          width: image.cropRect.width.toInt(),
          height: image.cropRect.height.toInt(),
        ),
      ),
      rotation: AnalysisRotation.values.byName(rotation.name),
    );
  }
}

/// Unwraps (converts) the [AnalysisImageWrapper] to a [AnalysisImage].
/// [AnalysisImageWrapper] is generated by pigeon and should not be handled by
/// end-user.
extension AnalysisUnwrapper on AnalysisImageWrapper {
  AnalysisImage unwrap() {
    switch (format) {
      case AnalysisImageFormat.yuv_420:
        return Yuv420Image(
          height: height,
          width: width,
          cropRect: Rect.fromLTWH(
            cropRect!.left.toDouble(),
            cropRect!.top.toDouble(),
            cropRect!.width.toDouble(),
            cropRect!.height.toDouble(),
          ),
          planes: planes!.map((p) => p!.unwrap()).toList(),
          format: InputAnalysisImageFormat.values.byName(format.name),
          rotation: InputAnalysisImageRotation.values.byName(rotation!.name),
        );
      case AnalysisImageFormat.bgra8888:
        return Bgra8888Image(
          height: height,
          width: width,
          planes: planes!.map((p) => p!.unwrap()).toList(),
          format: InputAnalysisImageFormat.values.byName(format.name),
          rotation: InputAnalysisImageRotation.values.byName(rotation!.name),
        );
      case AnalysisImageFormat.jpeg:
        return JpegImage(
          height: height,
          width: width,
          bytes: bytes!,
          cropRect: cropRect != null
              ? Rect.fromLTWH(
                  cropRect!.left.toDouble(),
                  cropRect!.top.toDouble(),
                  cropRect!.width.toDouble(),
                  cropRect!.height.toDouble(),
                )
              : null,
          format: InputAnalysisImageFormat.values.byName(format.name),
          rotation: InputAnalysisImageRotation.values.byName(rotation!.name),
        );
      case AnalysisImageFormat.nv21:
        return Nv21Image(
          height: height,
          width: width,
          bytes: bytes!,
          planes: planes!.map((p) => p!.unwrap()).toList(),
          cropRect: Rect.fromLTWH(
            cropRect!.left.toDouble(),
            cropRect!.top.toDouble(),
            cropRect!.width.toDouble(),
            cropRect!.height.toDouble(),
          ),
          format: InputAnalysisImageFormat.values.byName(format.name),
          rotation: InputAnalysisImageRotation.values.byName(rotation!.name),
        );
      case AnalysisImageFormat.unknown:
        throw "Unhandled format: $format";
    }
  }
}

/// Wraps (converts) the [ImagePlane] to a [PlaneWrapper].
/// [PlaneWrapper] is generated by pigeon and should not be handled by end-user.
extension PlaneWrap on ImagePlane {
  PlaneWrapper wrapped() {
    return PlaneWrapper(
      bytes: bytes,
      bytesPerRow: bytesPerRow,
      bytesPerPixel: bytesPerPixel,
      width: width,
      height: height,
    );
  }
}

/// Unwraps (converts) the [PlaneWrapper] to a [ImagePlane].
/// [PlaneWrapper] is generated by pigeon and should not be handled by end-user.
extension PlaneUnwrap on PlaneWrapper {
  ImagePlane unwrap() {
    return ImagePlane(
      width: width,
      height: height,
      bytes: bytes,
      bytesPerRow: bytesPerRow,
      bytesPerPixel: bytesPerPixel,
    );
  }
}
